import { getId } from './MapInfo';
import PathFinding from './PathFinding';

const { ccclass, property } = cc._decorator;

enum MoveType {
	None = 0,
	CreateBlock, //创建障碍
	RemoveBlock, //删除障碍
	MoveStartPoint, //移动起点
	MoveEndPoint, //移动终点
}

@ccclass
export default class Board extends cc.Component {
	@property
	gridSize: number = 40;

	@property(cc.Graphics)
	mapGraph: cc.Graphics = null;

	private _pathFinding: PathFinding;

	private _moveType = MoveType.None;
	private _touched: boolean = false;
	private _touchPoint = cc.v2();
	private _startPoint = cc.v2(5, 10);
	private _endPoint = cc.v2(10, 10);
	private _blocks = {};
	private _rect: cc.Rect;

	start() {
		this.drawBoard();
		this.drawMap();

		this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
		this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this);
		this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
		this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
	}

	private drawBoard() {
		const graph = this.node.getComponent(cc.Graphics);

		//背景
		const rect = new cc.Rect(-this.node.width * 0.5, -this.node.height * 0.5, this.node.width, this.node.height);
		this._rect = rect;
		this.fillRect(graph, cc.color(255, 255, 255, 200), rect.x, rect.y, rect.width, rect.height);

		//格子
		for (let i = 0, row = Math.ceil(rect.height / this.gridSize); i < row; i++) {
			for (let j = 0, col = Math.ceil(rect.width / this.gridSize); j < col; j++) {
				graph.strokeColor = cc.color(150, 150, 150);
				graph.rect(rect.x + this.gridSize * j, rect.y + this.gridSize * i, this.gridSize, this.gridSize);
				graph.stroke();
			}
		}
	}

	private drawMap(path?: cc.Vec2[]) {
		this.mapGraph.clear();

		//起始点
		this.fillRect(
			this.mapGraph,
			cc.color(0, 255, 40),
			this._rect.x + this.gridSize * this._startPoint.x,
			this._rect.y + this.gridSize * this._startPoint.y,
			this.gridSize,
			this.gridSize
		);
		//终点
		this.fillRect(
			this.mapGraph,
			cc.color(255, 0, 0),
			this._rect.x + Math.floor(this.gridSize * this._endPoint.x),
			this._rect.y + Math.floor(this.gridSize * this._endPoint.y),
			this.gridSize,
			this.gridSize
		);

		//障碍
		for (let i = 0, row = Math.ceil(this._rect.height / this.gridSize); i < row; i++) {
			for (let j = 0, col = Math.ceil(this._rect.width / this.gridSize); j < col; j++) {
				if (1 === this._blocks[getId(j, i)]) {
					this.fillRect(
						this.mapGraph,
						cc.color(100, 100, 100),
						this._rect.x + this.gridSize * j,
						this._rect.y + this.gridSize * i,
						this.gridSize,
						this.gridSize
					);
				}
			}
		}

		//路径
		if (path && path.length > 1) {
			const offset = this.gridSize * 0.5;
			this.mapGraph.lineWidth = 4;
			this.mapGraph.strokeColor = cc.Color.BLUE;

			this.mapGraph.moveTo(path[0].x * this.gridSize + offset + this._rect.x, this._rect.y + path[0].y * this.gridSize + offset);

			for (let i = 1; i < path.length; i++) {
				this.mapGraph.lineTo(this._rect.x + path[i].x * this.gridSize + offset, this._rect.y + path[i].y * this.gridSize + offset);
			}

			this.mapGraph.stroke();
		}
	}

	private fillRect = (graph: cc.Graphics, color: cc.Color, x: number, y: number, w: number, h: number) => {
		graph.rect(x, y, w, h);
		graph.fillColor = color;
		graph.fill();
	};

	private onTouchStart(event: cc.Event.EventTouch) {
		if (this._touched) {
			return;
		}

		this._touched = true;
		this._touchPoint.x = Math.floor(event.getLocationX() / this.gridSize);
		this._touchPoint.y = Math.floor(event.getLocationY() / this.gridSize);

		if (this._touchPoint.equals(this._startPoint)) {
			this._moveType = MoveType.MoveStartPoint;
		} else if (this._touchPoint.equals(this._endPoint)) {
			this._moveType = MoveType.MoveEndPoint;
		} else if (!this._blocks[getId(this._touchPoint.x, this._touchPoint.y)]) {
			this._moveType = MoveType.CreateBlock;
		} else {
			this._moveType = MoveType.RemoveBlock;
		}
	}

	private onTouchMove(event: cc.Event.EventTouch) {
		if (!this._touched) {
			return;
		}

		this._touchPoint.x = Math.floor(event.getLocationX() / this.gridSize);
		this._touchPoint.y = Math.floor(event.getLocationY() / this.gridSize);
		const id = getId(this._touchPoint.x, this._touchPoint.y);

		if (this._moveType == MoveType.CreateBlock) {
			if (!this._blocks[id]) {
				if (getId(this._startPoint.x, this._startPoint.y) != id && getId(this._endPoint.x, this._endPoint.y) != id) {
					this._blocks[id] = 1;
					this.drawMap();
				}
			}
		} else if (this._moveType == MoveType.RemoveBlock) {
			if (this._blocks[id]) {
				delete this._blocks[id];
				this.drawMap();
			}
		} else if (this._moveType == MoveType.MoveStartPoint) {
			if (!this._startPoint.equals(this._touchPoint)) {
				if (!this._blocks[id]) {
					this._startPoint.x = this._touchPoint.x;
					this._startPoint.y = this._touchPoint.y;
					this.drawMap();
				}
			}
		} else if (this._moveType == MoveType.MoveEndPoint) {
			if (!this._endPoint.equals(this._touchPoint)) {
				if (!this._blocks[id]) {
					this._endPoint.x = this._touchPoint.x;
					this._endPoint.y = this._touchPoint.y;
					this.drawMap();
				}
			}
		}
	}

	private onTouchEnd(event: cc.Event.EventTouch) {
		this.onTouchMove(event);
		this._touched = false;
		this._moveType = MoveType.None;

		if (!this._pathFinding) {
			this._pathFinding = this.node.getComponent(PathFinding);
		}
		const path = this._pathFinding.search(this._startPoint, this._endPoint, this._blocks);
		this.drawMap(path);
	}
}
